
#include "roc_statistic.h"
#include "saliency.h"
#include <stdio.h>
#include <string.h>
#include <iostream>

const char *g_roc_rate_fore_back[] = {
	"0",
	"0.1",
	"0.2",
	"0.3"
	"0.40~0.49",
	"0.50~0.59",
	"0.6",
	"0.7",
	"0.8",
	"0.9",
	"1.0",
	"", //for end
};

const char *g_roc_rate_adaboost[] = {
	"-100",
	"-20~20",
	"", //for end
};

const char *g_roc_rate_test[] = {
	"-4~4",
	"", //for end
};

static struct RocObject g_roc_object[ROC_LENGTH];
static int g_roc_length = 0;

void InitRoc() {
	//fill all the rate
	memset(g_roc_object, 0, sizeof(struct RocObject) * ROC_LENGTH);
    if (ROC_RATE_CHOICE == 0) {
        g_roc_length = StringAnalyse(g_roc_rate_adaboost, 1, g_roc_object);
    } else {
        //g_roc_length = StringAnalyse(g_roc_rate_fore_back, 0.02, g_roc_object);
        g_roc_length = StringAnalyse(g_roc_rate_test, 0.1, g_roc_object);

    }
}

int StringAnalyse(const char **roc_rate, float step, struct RocObject *roc_object) {
    int i;
    int index = 0;
    for (i = 0; strlen(roc_rate[i]) != 0; i++) {
		char *p = strchr((char *)roc_rate[i], '~');
		if (p == NULL) { //single value
			roc_object[index++].rate = atof(roc_rate[i]);
		} else { //process range
			char first[10] = {0};
			char last[10] = {0};
			float first_rate, last_rate;
			strncpy(first, roc_rate[i], p - roc_rate[i]);
			strcpy(last, p + 1);
			first_rate = atof(first);
			last_rate = atof(last);
			while (first_rate <= last_rate) {
				roc_object[index++].rate = first_rate;
				first_rate += step;
			}
		}
	}
    return index;
}

//for test
void PrintRoc() {
	int i = 0;
	for (i = 0; i < g_roc_length; i++) {
		printf("%f ", g_roc_object[i].rate);
	}
	printf("\n");
}
// tpr = TP / (TP + FN)
// fpr = FP / (FP + TN)
void WriteRoc() {
	FILE *fp = NULL;
	int i;
    if (ROC_RATE_CHOICE == 0) {
	    fp = fopen(ROC_RATE_ADABOOST_PATH, "w");
    } else {
	    fp = fopen(ROC_RATE_FOREBACK_PATH, "w");
    }
	if (fp == NULL) {
		printf("Can't open file %s.\n", "WriteRoc Related");
		exit(1);
	}
	fprintf(fp, "log rate, rate, pixel FPR, pixel TPR, ");
    if (ROC_RATE_CHOICE == 0) {
        fprintf(fp, "image count FPR, image count TPR, ");
    }
    fprintf(fp, "\n");
	for (i = 0; i < g_roc_length; i++) {
		float true_positive_rate_ave = g_roc_object[i].true_positive_cnt_sum / (float)(g_roc_object[i].true_positive_cnt_sum + g_roc_object[i].false_negative_cnt_sum);
        float false_positive_rate_ave = g_roc_object[i].false_positive_cnt_sum / (float)(g_roc_object[i].false_positive_cnt_sum + g_roc_object[i].true_negative_cnt_sum);
        fprintf(fp, "%f, %f, %f, %f, ", g_roc_object[i].rate, pow(10.0, (double)g_roc_object[i].rate), false_positive_rate_ave, true_positive_rate_ave);
        if (ROC_RATE_CHOICE == 0) {
            true_positive_rate_ave = g_roc_object[i].true_positive_cnt_sum_image / (float)(g_roc_object[i].true_positive_cnt_sum_image + g_roc_object[i].false_negative_cnt_sum_image);
            false_positive_rate_ave = g_roc_object[i].false_positive_cnt_sum_image / (float)(g_roc_object[i].false_positive_cnt_sum_image + g_roc_object[i].true_negative_cnt_sum_image);
            fprintf(fp, "%f, %f, ", false_positive_rate_ave, true_positive_rate_ave);
        }
        fprintf(fp, "\n");
		/*printf("%f : %d, %d, %d, %d, %d\n", g_roc_object[i].rate, g_roc_object[i].true_positive_cnt_sum, 
            g_roc_object[i].false_negative_cnt_sum, g_roc_object[i].false_positive_cnt_sum, 
            g_roc_object[i].true_negative_cnt_sum, g_roc_object[i].count);*/
	}
	fclose(fp);
}

int FloatCompare(const void *lhs, const void *rhs) {
	float a = *(float *)lhs;
	float b = *(float *)rhs;
    if (a > b) {
		return 1;
    } else if (a < b) {
		return -1;
    } else {
		return 0;
    }
}
void ForeBackRocRate(float *result_fore, float *result_back, int width, int height, unsigned char *label_img_data) {
	int x, y;
	float rate;
	int img_width_step = CALCULATE_STEP_THREE(width);
	int res_width_step = width;
	float max_f = FLOAT_MIN, min_f = FLOAT_MAX;
	float result_tmp[ONE_CHANNEL_IMAGE_MAX_PIXEL] = {0.0};
	int i;
	
	for (i = 0; i < g_roc_length; i++) {
		float threshold_rate = g_roc_object[i].rate;
		int true_positive_cnt = 0;
		int true_negative_cnt = 0;
		int false_positive_cnt = 0;
		int false_negative_cnt = 0;
		int result_value, label_value;

		for (y = 0; y < height; y++) {
			for (x = 0; x < width; x++) {
                float fore_prob = IMAGE_ELEM(result_fore, float, res_width_step, x, y);
                float back_prob = IMAGE_ELEM(result_back, float, res_width_step, x, y);
				
				//rate = IMAGE_ELEM(result_fore, float, res_width_step, x, y) / (IMAGE_ELEM(result_fore, float, res_width_step, x, y) + IMAGE_ELEM(result_back, float, res_width_step, x, y));
				//minus
                //rate = IMAGE_ELEM(result_fore, float, res_width_step, x, y) - IMAGE_ELEM(result_back, float, res_width_step, x, y);
				//IMAGE_ELEM(result_tmp, float, width, x, y) = rate;
				//rate = rate > threshold_rate ? rate : 0;
                
                //division
                //rate = IMAGE_ELEM(result_fore, float, res_width_step, x, y) / IMAGE_ELEM(result_back, float, res_width_step, x, y);
                //log division
                rate = log10(fore_prob) - log10(back_prob);
				if (rate >= threshold_rate) {
					result_value = 255;
				} else {
					result_value = 0;
				}
				label_value = 0; //default;
				if (label_img_data != NULL) {
					label_value = IMAGE_ELEM(label_img_data, unsigned char, img_width_step, x * 3, y);
				} 
				if (label_value > 0 && result_value > 0) { true_positive_cnt++; }
				if (label_value == 0 && result_value == 0) { true_negative_cnt++; }
				if (label_value > 0 && result_value == 0) { false_negative_cnt++; }
				if (label_value == 0 && result_value > 0) { false_positive_cnt++; }
			}
		}
		//qsort(result_tmp, width * height, sizeof(float), FloatCompare);
		
		//WriteToFileFloat("float.txt", result_tmp, width, height, 1);
		g_roc_object[i].true_positive_cnt_sum += true_positive_cnt;
		g_roc_object[i].true_negative_cnt_sum += true_negative_cnt;
		g_roc_object[i].false_negative_cnt_sum += false_negative_cnt;
		g_roc_object[i].false_positive_cnt_sum += false_positive_cnt;
	}
}

void ForeBackRocRateNoSaliency(int width, int height, unsigned char *label_img_data) {
	int x, y;
	float rate;
	int img_width_step = CALCULATE_STEP_THREE(width);
	int res_width_step = width;
	float max_f = FLOAT_MIN, min_f = FLOAT_MAX;
	int i;

	//float to unsigned char data
	for (i = 0; i < g_roc_length; i++) {
		int true_positive_cnt = 0;
		int true_negative_cnt = 0;
		int false_positive_cnt = 0;
		int false_negative_cnt = 0;

		for (y = 0; y < height; y++) {
			for (x = 0; x < width; x++) {
				int result_value = 0; //no saliency
				int label_value = 0; //default;
				if (label_img_data != NULL) {
					label_value = IMAGE_ELEM(label_img_data, unsigned char, img_width_step, x * 3, y);
				} 
				if (label_value > 0 && result_value > 0) { true_positive_cnt++; }
				if (label_value == 0 && result_value == 0) { true_negative_cnt++; }
				if (label_value > 0 && result_value == 0) { false_negative_cnt++; }
				if (label_value == 0 && result_value > 0) { false_positive_cnt++; }
			}
		}
		g_roc_object[i].true_positive_cnt_sum += true_positive_cnt;
		g_roc_object[i].true_negative_cnt_sum += true_negative_cnt;
		g_roc_object[i].false_negative_cnt_sum += false_negative_cnt;
		g_roc_object[i].false_positive_cnt_sum += false_positive_cnt;
	}
}

void YonRocRate(float *index_float, unsigned char *cluster_map, int width, int height, unsigned char *label_img_data) {
	int x, y;
	float rate;
	int img_width_step = CALCULATE_STEP_THREE(width);
	int res_width_step = width;
	float max_f = FLOAT_MIN, min_f = FLOAT_MAX;
	int i;
	
	for (i = 0; i < g_roc_length; i++) {
		float threshold_rate = g_roc_object[i].rate;
		int true_positive_cnt = 0;
		int true_negative_cnt = 0;
		int false_positive_cnt = 0;
		int false_negative_cnt = 0;
		int result_value, label_value;

		for (y = 0; y < height; y++) {
			for (x = 0; x < width; x++) {
				rate = index_float[IMAGE_ELEM(cluster_map, unsigned char, width, x, y)];
				if (rate >= threshold_rate) {
					result_value = 255;
				} else {
					result_value = 0;
				}
				label_value = 0; //default;
				if (label_img_data != NULL) {
					label_value = IMAGE_ELEM(label_img_data, unsigned char, img_width_step, x * 3, y);
				} 
				if (label_value > 0 && result_value > 0) { true_positive_cnt++; }
				if (label_value == 0 && result_value == 0) { true_negative_cnt++; }
				if (label_value > 0 && result_value == 0) { 
					false_negative_cnt++; 
				}
				if (label_value == 0 && result_value > 0) { 
					false_positive_cnt++; 
				}
			}
		}
		g_roc_object[i].true_positive_cnt_sum += true_positive_cnt;
		g_roc_object[i].true_negative_cnt_sum += true_negative_cnt;
		g_roc_object[i].false_negative_cnt_sum += false_negative_cnt;
		g_roc_object[i].false_positive_cnt_sum += false_positive_cnt;
	}
	
}

void SaliencyCountRocRate(float *index_float, int *cluster_count, unsigned char *label_img_data, int width, int height) {
    int i, j;
    int x, y;
    int label_value = 0;
    int img_width_step = CALCULATE_STEP_THREE(width);
    //check the label image saliency
    if (label_img_data != NULL) {
        for (y = 0; y < height; y++) {
			for (x = 0; x < width; x++) {
                int label_pixel = IMAGE_ELEM(label_img_data, unsigned char, img_width_step, x * 3, y);
                if (label_pixel > 0) {
                    label_value = 1;
                    break;
                }
            }
        }
    }
    for (i = 0; i < g_roc_length; i++) {
        float threshold_rate = g_roc_object[i].rate;
        int saliency_points = 0;
        int result_value = 0;
        for (j = 0; j < CLUSTER_SIZE; j++) {
            if (index_float[j] > threshold_rate) {
                saliency_points += cluster_count[j];
            }
        }
        if (saliency_points > SALIENCY_HAVE_THRESHOLD) {
            result_value = 1; //have saliency
        }
        if (label_value > 0 && result_value > 0) { g_roc_object[i].true_positive_cnt_sum_image++; }
        if (label_value == 0 && result_value == 0) { g_roc_object[i].true_negative_cnt_sum_image++; }
        if (label_value > 0 && result_value == 0) { g_roc_object[i].false_negative_cnt_sum_image++; }
        if (label_value == 0 && result_value > 0) { g_roc_object[i].false_positive_cnt_sum_image++; }

    }
}